#include "error.hpp"
#include "parser.hpp"
#include <cstdlib>

void yyerror(const char* st) {
    cout << "Erro sintático em stdin:" << numLinha << ":"
            << numCol << ": " << endl;
    cout << "    * Última linha: " << ultimaLinha << endl
            << "    * Último token: " << ultimoToken << endl;
    cout << "Compilação interrompida devido aos erros.\n";
    exit(0);
}

// class Error

void Error::panic(const char* file, int linha, string msg) {
    cout << "Pânico! Erro interno em " << file << ":" << linha << ": "
         << msg << endl;
    exit(0);
}

void Error::abort(string msg) {
    cout << "Erro semântico em stdin:" << numLinha << ":"
            << numCol << ": " << msg << endl;
    cout << "    * Última linha: " << ultimaLinha << endl
            << "    * Último token: " << ultimoToken << endl;
    cout << "Compilação interrompida devido aos erros.\n";
    exit(0);
}

void Error::dupid(string name, Type* type) {
    string msg = "Variável já declarada: " + name + " : " + type->name();
    abort(msg);
}

void Error::inctypesassign(Properties &id, Properties& exp) {
    string msg = "Atribuição ilegal: " + exp.type->name() +
            " não pode ser atribuído a " + id.value + " : " + id.type->name();
    abort(msg);
}

void Error::inctypeslist(Type* listtype, Properties& var) {
    string msg = "Elementos heterogêneos: O elemento " + var.value + " : " +
            var.type->name() + " não pode figurar em um vetor de tipo " +
            listtype->name();
    abort(msg);
}

void Error::opundef(Properties& opl, Properties& opr, string ops) {
    string msg = "Operação não definida: " + opl.type->name() + " " + ops +
            " " + opr.type->name();
    abort(msg);

}

void Error::negundef(Properties& var, string op) {
    string msg = "Negação não definida: " + op + var.type->name();
    abort(msg);
}

void Error::decmiss(string name) {
    abort("Variável não declarada: " + name);
}

void Error::swapwrong(Properties& var1, Properties& var2) {
    string msg = "Permutação entre tipos incompatíveis: " + var1.value + " : " +
            var1.type->name() + " e " + var2.value + " : " + var2.type->name();
    abort(msg);
}

void Error::nonlogictest(Properties& test) {
    string msg = "Expressão não-lógica em teste: " + test.type->name();
    abort(msg);
}

void Error::notarray(Properties& array, Properties& index) {
    string msg = "Indexação de variável simples: " + 
            array.type->dec(array.value) + " com índice " +
            index.type->dec(index.value);
    abort(msg);
}

void Error::notindex(Properties& array, Properties& index) {
    string msg = "Indexação de array com índice não-inteiro: " +
            array.type->dec(array.value) + " com índice " +
            index.type->dec(index.value);
    abort(msg);
}

void Error::printcomplex(Properties& var) {
    abort("Impressão de tipo composto: " + var.type->dec(var.value));
}
void Error::scancomplex(Properties& var) {
    abort("Leitura para tipo composto: " + var.type->dec(var.value));
}

void Error::scantoconst(Properties& var) {
    abort("Leitura para constante: " + var.type->dec(var.value));
}

void Error::nonintindex(Properties& index) {
    abort("Variável de iteração não inteira: " + index.type->dec(index.value));
}

void Error::nonnumericl(Properties& a, Properties& b) {
    string msg = "Limites de iteração não numéricos: " + a.type->dec(a.value) +
            " e " + b.type->dec(b.value);
    abort(msg);
}

void Error::dupmap(Function* m1, Function* m2) {
    string msg = "Mapeamento " + m2->dec() + " é idêntico ou indisgtinguível" +
            + " do mapeamento já definido " + m1->dec();
    abort(msg);
}

void Error::mapundef(Function* map) {
    abort("Mapeamento " + map->dec() + " não definido");
}